package com.abocode.smarten.server.utils;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
 * @author: guanxianfei
 * @date: 2019/1/5
 */
@Slf4j
public class BeanUtils extends org.springframework.beans.BeanUtils {


	/**
	 * 对象属性拷贝
	 */
	public static <T> T copyProperties(final Object source, final Class<T> clazz) {
		T target;
		try {
			target = clazz.newInstance();
			copyProperties(source, target);
		} catch (Exception e) {
			log.error("Object property copy error. ", e);
			throw new RuntimeException("Object property copy error");
		}
		return target;
	}

	/**
	 * 批量对象属性拷贝
	 */
	public static <E, V> List<V> copyProperties(final List<E> sourceList, final Class<V> clazz) {
		Assert.notNull(sourceList, "Source must not be null");
		return sourceList.stream().map(pojo -> copyProperties(pojo, clazz)).collect(Collectors.toList());
	}

	/**
	 * 对象属性拷贝
	 */
	public static void copyNotNullProperties(final Object source, final Object target) {
		try {
			copyProperties(source, target, setIgnoreNull(source));
		} catch (Exception e) {
			log.error("Object property copy error", e);
			throw new RuntimeException("Object property copy error");
		}
	}

	/**
	 * 该方法的参数列表是一个类的类名、成员变量、给变量的赋值
	 *
	 * @param obj
	 * @param propertyName
	 * @param value
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 */
	public static void setProperty(Object obj, String propertyName, Object value)
			throws NoSuchFieldException, IllegalAccessException {
		Class c = obj.getClass();
		Field f = c.getDeclaredField(propertyName);
		f.setAccessible(true);
		f.set(obj, value);
	}

	/**
	 * 忽略空属性
	 *
	 * @param source
	 * @return
	 */
	private static String[] setIgnoreNull(Object source) {
		final BeanWrapper wrapper = new BeanWrapperImpl(source);
		PropertyDescriptor[] pds = wrapper.getPropertyDescriptors();
		Set<String> emptyNames = new HashSet<>();
		for (PropertyDescriptor pd : pds) {
			Object srcValue = wrapper.getPropertyValue(pd.getName());
			if (ObjectUtils.isEmpty(srcValue)) {
				emptyNames.add(pd.getName());
			}
		}
		String[] result = new String[emptyNames.size()];
		return emptyNames.toArray(result);
	}

}